package handler

import (
	"context"
	"github.com/golang/protobuf/ptypes/empty"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"pm_back_server/project-server/global"
	"pm_back_server/project-server/model"
	"pm_back_server/project-server/proto"
	"pm_back_server/project-server/utils"
)

func HandleGroupModelToResponse(groupModel *model.Group) *proto.GroupResponseInfo {
	return &proto.GroupResponseInfo{
		Id:             uint64(groupModel.ID),
		Name:           groupModel.Name,
		Desc:           groupModel.Desc,
		Cover:          groupModel.Cover,
		InvitationCode: groupModel.InvitationCode,
		LeaderId:       groupModel.LeaderId,
	}
}

// CreateGroup /* 创建团队
func (p *ProjectServer) CreateGroup(ctx context.Context, req *proto.CreateGroupInfo) (*proto.GroupResponseInfo, error) {
	invitationCode := utils.GenUuid()

	group := model.Group{
		Name:           req.Name,
		Desc:           req.Desc,
		Cover:          req.Cover,
		LeaderId:       req.LeaderId,
		InvitationCode: invitationCode,
	}
	result := global.DB.Create(&group)
	if result.Error != nil {
		zap.S().Errorw("[CreateGroup] 创建 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	userGroup := model.UserGroup{
		GroupId: uint64(group.ID),
		UserId:  req.LeaderId,
	}

	result = global.DB.Create(&userGroup)
	if result.Error != nil {
		zap.S().Errorw("[CreateGroup] 创建 [用户 - 项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return HandleGroupModelToResponse(&group), nil
}

// GetGroupById /* 通过ID查询团队
func (p *ProjectServer) GetGroupById(ctx context.Context, req *proto.GroupIdInfo) (*proto.GroupResponseInfo, error) {
	var group model.Group

	result := global.DB.First(&group, req.Id)

	if result.Error != nil {
		zap.S().Errorw("[GetGroupById] 查询 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	if result.RowsAffected == 0 {
		zap.S().Errorw("[GetGroupById] 查询 [项目] 失败")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}

	return HandleGroupModelToResponse(&group), nil
}

// GetGroupByName /* 通过团队名称查询团队
func (p *ProjectServer) GetGroupByName(ctx context.Context, req *proto.GroupNameInfo) (*proto.GroupResponseInfo, error) {
	var group model.Group

	result := global.DB.Where(&model.Group{Name: req.Name}).First(&group)

	if result.RowsAffected == 0 {
		zap.S().Errorw("[GetGroupByName] 查询 [项目] 失败")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}

	if result.Error != nil {
		zap.S().Errorw("[GetGroupByName] 查询 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return HandleGroupModelToResponse(&group), nil
}

// UpdateGroup /* 更新团队信息
func (p *ProjectServer) UpdateGroup(ctx context.Context, req *proto.UpdateGroupInfo) (*empty.Empty, error) {
	var group model.Group
	result := global.DB.First(&group, req.Id)
	if result.RowsAffected == 0 {
		zap.S().Errorw("[UpdateGroup] 查询 [项目] 失败")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}

	if !CheckUserExistInGroup(req.Id, req.LeaderId) {
		zap.S().Errorw("[UpdateGroup] 检验 [权限] 失败")
		return nil, status.Errorf(codes.Unavailable, "用户不存在团队中")
	}

	group.Name = req.Name
	group.Desc = req.Desc
	group.Cover = req.Cover
	group.LeaderId = req.LeaderId

	result = global.DB.Save(&group)

	if result.Error != nil {
		zap.S().Errorw("[UpdateGroup] 更新 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return &empty.Empty{}, nil
}

// DeleteGroup /* 删除团队
func (p *ProjectServer) DeleteGroup(ctx context.Context, req *proto.DeleteGroupInfo) (*empty.Empty, error) {
	// 查询团队是否存在
	var group model.Group
	result := global.DB.First(&group, req.Id)
	if result.RowsAffected == 0 {
		zap.S().Errorw("[DeleteGroup] 查询 [项目] 失败")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}
	// 校验是否具有权限
	if group.LeaderId != req.LeaderId {
		zap.S().Errorw("[DeleteGroup] 检验 [权限] 失败")
		return nil, status.Errorf(codes.Unavailable, Unavailable)
	}
	// 删除团队时，还要删除团队所属的项目
	if err := p.DeleteProjectByGroupId(&proto.GroupIdInfo{Id: req.Id}); err != nil {
		return nil, status.Errorf(codes.Internal, err.Error())
	}
	// 删除团队所属迭代
	if err := p.DeleteIterationByGroupId(&proto.GroupIdInfo{Id: req.Id}); err != nil {
		return nil, status.Errorf(codes.Internal, err.Error())
	}
	// 删除团队所属任务
	if err := p.DeleteTaskByGroupId(&proto.GroupIdInfo{Id: req.Id}); err != nil {
		return nil, status.Errorf(codes.Internal, err.Error())
	}
	// 删除团队
	result = global.DB.Delete(&group, req.Id)
	if result.Error != nil {
		zap.S().Errorw("[DeleteGroup] 删除 [项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	// 删除用户 - 团队关系
	var userGroup []model.UserGroup
	result = global.DB.Model(&model.UserGroup{}).Where("group_id = ?", req.Id).Delete(&userGroup)
	if result.Error != nil {
		zap.S().Errorw("[DeleteGroup] 删除 [用户 - 项目] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}
	return &empty.Empty{}, nil
}

// JoinGroup /* 加入团队
func (p *ProjectServer) JoinGroup(ctx context.Context, req *proto.GroupMemberInfo) (*empty.Empty, error) {
	var group model.Group
	result := global.DB.First(&group, req.GroupId)
	if result.RowsAffected == 0 {
		zap.S().Errorw("[JoinGroup] 查询 [团队] 失败")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}

	var userGroup model.UserGroup
	result = global.DB.Model(&model.UserGroup{}).Where("user_id", req.UserId).First(&userGroup)
	if result.RowsAffected == 1 {
		zap.S().Errorw("[JoinGroup] 查询 [用户] 失败")
		return nil, status.Errorf(codes.AlreadyExists, "用户已存在")
	}

	userGroup = model.UserGroup{
		GroupId: req.GroupId,
		UserId:  req.UserId,
	}
	result = global.DB.Create(&userGroup)
	if result.Error != nil {
		zap.S().Errorw("[JoinGroup] 创建 [用户 - 团队] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return &empty.Empty{}, nil
}

// ExitGroup /* 离开团队
func (p *ProjectServer) ExitGroup(ctx context.Context, req *proto.GroupMemberInfo) (*empty.Empty, error) {
	var group model.Group
	result := global.DB.First(&group, req.GroupId)
	if result.RowsAffected == 0 {
		zap.S().Errorw("[ExitGroup] 查询 [团队] 失败")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}
	// 当userId为leaderId时 删除团队
	if group.LeaderId == req.UserId {
		_, err := p.DeleteGroup(ctx, &proto.DeleteGroupInfo{
			Id:       req.GroupId,
			LeaderId: req.UserId,
		})
		if err != nil {
			zap.S().Errorw("[ExitGroup] 删除 [团队] 失败")
			return nil, status.Errorf(codes.Internal, result.Error.Error())
		}
		return &empty.Empty{}, nil
	}

	var userGroup model.UserGroup
	result = global.DB.Model(&model.UserGroup{}).Where("group_id = ? AND user_id = ?", req.GroupId, req.UserId).First(&userGroup)
	if result.RowsAffected == 0 {
		zap.S().Errorw("[ExitGroup] 查询 [用户 - 团队] 失败")
		return nil, status.Errorf(codes.NotFound, UserGroupNotFoundStr)
	}

	result = global.DB.Model(&model.UserGroup{}).Where("group_id = ? AND user_id = ?", req.GroupId, req.UserId).Delete(&userGroup)
	if result.Error != nil {
		zap.S().Errorw("[ExitGroup] 删除 [用户 - 团队] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	return &empty.Empty{}, nil
}

// GetMemberList /* 获取团队成员列表
func (p *ProjectServer) GetMemberList(ctx context.Context, req *proto.GroupIdInfo) (*proto.MemberResponseListInfo, error) {
	var group model.Group
	result := global.DB.First(&group, req.Id)
	if result.RowsAffected == 0 {
		zap.S().Errorw("[GetMemberList] 查询 [团队] 失败")
		return nil, status.Errorf(codes.NotFound, GroupNotFoundStr)
	}

	var userGroups []model.UserGroup
	result = global.DB.Model(&model.UserGroup{}).Where("group_id = ?", req.Id).Find(&userGroups)
	if result.Error != nil {
		zap.S().Errorw("[GetMemberList] 查询 [团队成员列表] 失败")
		return nil, status.Errorf(codes.Internal, result.Error.Error())
	}

	rsp := &proto.MemberResponseListInfo{
		GroupId: req.Id,
	}

	for _, userGroup := range userGroups {
		rsp.MemberList = append(rsp.MemberList, &proto.MemberResponseInfo{
			UserId: userGroup.UserId,
		})
	}

	return rsp, nil
}

// CheckAuthority /* 检查是否有权限
func CheckAuthority(groupId uint64, userId uint64) bool {
	var group model.Group
	_ = global.DB.First(&group, groupId)
	if group.LeaderId != userId {
		return false
	}
	return true
}

// CheckUserExistInGroup /* 检查用户是否存在团队中
func CheckUserExistInGroup(groupId uint64, userId uint64) bool {
	var userGroup model.UserGroup
	result := global.DB.Model(&model.UserGroup{}).Where("group_id = ? AND user_id = ?", groupId, userId).First(&userGroup)
	if result.RowsAffected == 0 {
		return false
	}
	return true
}

// CheckGroupExist /* 检查团队是否存在
func CheckGroupExist(groupId uint64) bool {
	var group model.Group
	result := global.DB.First(&group, groupId)
	if result.RowsAffected == 0 {
		return false
	}
	return true
}
